package websocket

import (
	"encoding/binary"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"sen-golang-study/go_game_study/hero_story_go_server/game_server/internal/application/service"
	"sen-golang-study/go_game_study/hero_story_go_server/game_server/internal/infrastructure/async"
	"sen-golang-study/go_game_study/hero_story_go_server/game_server/internal/interfaces/context"
	"sen-golang-study/go_game_study/hero_story_go_server/game_server/internal/interfaces/handler"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

// WebSocketHandler WebSocket处理器
type WebSocketHandler struct {
	upgrader                 websocket.Upgrader
	cmdHandlerFactory        *handler.CmdHandlerFactory
	sessionManagementService *service.SessionManagementService
	contexts                 *sync.Map // sessionID -> context.CmdContext
	mutex                    sync.RWMutex
}

// NewWebSocketHandler 创建WebSocket处理器
func NewWebSocketHandler(cmdHandlerFactory *handler.CmdHandlerFactory, sessionManagementService *service.SessionManagementService) *WebSocketHandler {
	return &WebSocketHandler{
		upgrader: websocket.Upgrader{
			CheckOrigin: func(r *http.Request) bool {
				return true // 允许所有来源
			},
		},
		cmdHandlerFactory:        cmdHandlerFactory,
		sessionManagementService: sessionManagementService,
		contexts:                 &sync.Map{},
	}
}

// HandleWebSocket 处理WebSocket连接
func (h *WebSocketHandler) HandleWebSocket(w http.ResponseWriter, r *http.Request) {
	// 升级HTTP连接为WebSocket连接
	conn, err := h.upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Printf("Failed to upgrade connection: %v", err)
		return
	}
	defer func() {
		if err := conn.Close(); err != nil {
			log.Printf("Failed to close WebSocket connection: %v", err)
		}
	}()

	// 获取客户端IP地址
	clientIP := r.RemoteAddr
	if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
		clientIP = forwarded
	}

	// 生成会话ID
	sessionID := h.generateSessionID()

	// 创建消息通道
	msgChan := make(chan *async.AsyncResult, 100)

	// 创建命令上下文
	ctx := context.NewWebSocketCmdContext(sessionID, clientIP, msgChan)
	ctx.SetSessionID(sessionID)

	// 创建会话
	_, err = h.sessionManagementService.CreateSession(sessionID, 0, 0, clientIP)
	if err != nil {
		log.Printf("Failed to create session: %v", err)
		return
	}

	// 存储上下文
	h.contexts.Store(sessionID, ctx)
	defer func() {
		h.contexts.Delete(sessionID)
		if err := h.sessionManagementService.RemoveSession(sessionID); err != nil {
			log.Printf("Failed to remove session %s: %v", sessionID, err)
		}
	}()

	log.Printf("WebSocket connection established: sessionID=%s, clientIP=%s", sessionID, clientIP)

	// 启动消息发送协程
	go h.loopSendMsg(conn, msgChan)

	// 启动消息接收循环
	h.loopReadMsg(conn, ctx)
}

// loopSendMsg 消息发送循环
func (h *WebSocketHandler) loopSendMsg(conn *websocket.Conn, msgChan chan *async.AsyncResult) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("Send message loop panic: %v", r)
		}
	}()

	for {
		select {
		case result, ok := <-msgChan:
			if !ok {
				// 通道已关闭
				return
			}

			if result == nil {
				continue
			}

			// 获取消息内容
			msgData, ok := result.GetReturnValue().(map[string]interface{})
			if !ok {
				continue
			}

			msgCode, ok := msgData["msgCode"].(uint16)
			if !ok {
				continue
			}

			msgBody := msgData["msgBody"]

			// 序列化消息体
			msgBodyBytes, err := json.Marshal(msgBody)
			if err != nil {
				log.Printf("Failed to marshal message body: %v", err)
				continue
			}

			// 构造完整消息
			fullMsg := h.buildMessage(msgCode, msgBodyBytes)

			// 发送消息
			err = conn.WriteMessage(websocket.BinaryMessage, fullMsg)
			if err != nil {
				log.Printf("Failed to write message: %v", err)
				return
			}

			// 检查是否为断开连接消息
			if msgCode == 65535 {
				return
			}
		case <-time.After(30 * time.Second):
			// 发送心跳消息
			heartbeat := h.buildMessage(0, []byte("{}"))
			err := conn.WriteMessage(websocket.BinaryMessage, heartbeat)
			if err != nil {
				log.Printf("Failed to send heartbeat: %v", err)
				return
			}
		}
	}
}

// loopReadMsg 消息接收循环
func (h *WebSocketHandler) loopReadMsg(conn *websocket.Conn, ctx context.CmdContext) {
	defer func() {
		if r := recover(); r != nil {
			log.Printf("Read message loop panic: %v", r)
		}
		ctx.Disconnect()
	}()

	for {
		// 读取消息
		msgType, msgData, err := conn.ReadMessage()
		if err != nil {
			log.Printf("Failed to read message: %v", err)
			break
		}

		// 只处理二进制消息
		if msgType != websocket.BinaryMessage {
			continue
		}

		// 解析消息
		msgCode, msgBody, err := h.parseMessage(msgData)
		if err != nil {
			log.Printf("Failed to parse message: %v", err)
			continue
		}

		// 更新会话活跃时间
		if err := h.sessionManagementService.UpdateSessionActivity(ctx.GetSessionID()); err != nil {
			log.Printf("Failed to update session activity for session %s: %v", ctx.GetSessionID(), err)
		}

		// 获取命令处理器
		cmdHandler := h.cmdHandlerFactory.CreateHandler(msgCode)
		if cmdHandler == nil {
			log.Printf("No handler found for message code: %d", msgCode)
			continue
		}

		// 异步处理命令
		go func(handler handler.CmdHandlerFunc, context context.CmdContext, body []byte) {
			defer func() {
				if r := recover(); r != nil {
					log.Printf("Command handler panic: %v", r)
				}
			}()
			handler(context, body)
		}(cmdHandler, ctx, msgBody)
	}
}

// generateSessionID 生成会话ID
func (h *WebSocketHandler) generateSessionID() string {
	return fmt.Sprintf("session_%d_%d", time.Now().UnixNano(), time.Now().Unix())
}

// buildMessage 构造消息
func (h *WebSocketHandler) buildMessage(msgCode uint16, msgBody []byte) []byte {
	msgLen := uint32(len(msgBody))
	fullMsg := make([]byte, 6+msgLen)

	// 消息长度 (4字节)
	binary.LittleEndian.PutUint32(fullMsg[0:4], msgLen)
	// 消息码 (2字节)
	binary.LittleEndian.PutUint16(fullMsg[4:6], msgCode)
	// 消息体
	copy(fullMsg[6:], msgBody)

	return fullMsg
}

// parseMessage 解析消息
func (h *WebSocketHandler) parseMessage(msgData []byte) (uint16, []byte, error) {
	if len(msgData) < 6 {
		return 0, nil, fmt.Errorf("message too short")
	}

	// 解析消息长度
	msgLen := binary.LittleEndian.Uint32(msgData[0:4])
	// 解析消息码
	msgCode := binary.LittleEndian.Uint16(msgData[4:6])
	// 解析消息体
	msgBody := msgData[6:]

	if uint32(len(msgBody)) != msgLen {
		return 0, nil, fmt.Errorf("message length mismatch")
	}

	return msgCode, msgBody, nil
}

// GetContext 获取上下文
func (h *WebSocketHandler) GetContext(sessionID string) (context.CmdContext, bool) {
	value, exists := h.contexts.Load(sessionID)
	if !exists {
		return nil, false
	}
	return value.(context.CmdContext), true
}

// GetAllContexts 获取所有上下文
func (h *WebSocketHandler) GetAllContexts() []context.CmdContext {
	var contexts []context.CmdContext
	h.contexts.Range(func(key, value interface{}) bool {
		contexts = append(contexts, value.(context.CmdContext))
		return true
	})
	return contexts
}

// CloseConnection 关闭连接
func (h *WebSocketHandler) CloseConnection(sessionID string) {
	if ctx, exists := h.GetContext(sessionID); exists {
		ctx.Disconnect()
	}
}
